package com.hulk.ratel.framework.config;


import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.lang.reflect.Method;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @Author: hulk
 * @E-mail: 29572320@qq.com
 * @Date: Create in 2018/9/20 下午2:43
 * @Version: 1.0.0
 * @Modify by:
 * Class description
 */
@Slf4j
@Configuration(proxyBeanMethods = false)
@EnableAsync
public class ExecutorAsyncConfig implements AsyncConfigurer {

	private static final int PROCESSORS = Runtime.getRuntime().availableProcessors();
	/**
	 * Set the ThreadPoolExecutor's core pool size.
	 */
	private static final int COREPOOL_SIZE = PROCESSORS;
	/**
	 * Set the ThreadPoolExecutor's maximum pool size.
	 */
	private static final int MAXPOOL_SIZE = PROCESSORS * 2;
	/**
	 * Set the capacity for the ThreadPoolExecutor's BlockingQueue.
	 */
	private static final int QUEUE_CAPACITY = PROCESSORS * 3;


	/**通用线程池*/
	@Override
	public Executor getAsyncExecutor() {
		ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
		executor.setCorePoolSize(COREPOOL_SIZE);
		executor.setMaxPoolSize(MAXPOOL_SIZE);
		executor.setQueueCapacity(QUEUE_CAPACITY);
		executor.setThreadNamePrefix("asyncConfigurer-");

		// rejection-policy：当pool已经达到max size的时候，如何处理新任务
		// CALLER_RUNS：不在新线程中执行任务，而是由调用者所在的线程来执行
		executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
		executor.initialize();
		return executor;
	}
	/**异步任务中异常处理*/
	@Override
	public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
		return (ex, arg1, arg2) -> {
			log.error("ex:{},exception method:{}", ex.getMessage(), arg1.getName());
			for (Object param : arg2) {
				log.info("Parameter value - " + param);
			}
		};
	}


}
